package org.scohen.juploadr.app.state;

import java.beans.XMLDecoder;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import org.apache.commons.beanutils.BeanUtils;
import org.scohen.juploadr.Messages;
import org.scohen.juploadr.app.ImageAttributes;
import org.scohen.juploadr.app.JUploadr;
import org.scohen.juploadr.app.PhotoSet;
import org.scohen.juploadr.app.geo.GeoLocation;
import org.scohen.juploadr.ui.ReusableUIFactory;
import org.scohen.juploadr.ui.Task;
import org.scohen.juploadr.uploadapi.ImageUploadApi;
import org.scohen.juploadr.uploadapi.abilities.Abilities;
import org.scohen.juploadr.uploadapi.abilities.OrganizeAbilities;

public class RestoreStateTask extends Task {
    private JUploadr uploadr;
    private Preferences prefs = Preferences.userNodeForPackage(SaveStateTask.class);
    private String[] keys;
    private Map<String, ImageStateDescriptor> imageStates;

    public RestoreStateTask(JUploadr uploadr) {
        imageStates = new HashMap<String, ImageStateDescriptor>();
        this.uploadr = uploadr;
        this.min = 0;
        try {
            this.keys = prefs.keys();
            this.max = countPhotos(keys);
        } catch (BackingStoreException e) {
            keys = new String[0];

            this.max = keys.length;
        }

    }

    private int countPhotos(String[] keys) {
        int numPhotos = 0;
        for (int i = 0; i < keys.length; i++) {
            String key = keys[i];
            if (key.indexOf(".path") > 0) {
                numPhotos++;
            }
        }
        return numPhotos;
    }

    public void execute() {
        for (int i = 0; i < keys.length; i++) {
            int sequence = Integer.parseInt(keys[i].substring(0, keys[i].indexOf('.')));
            String key = keys[i].substring(keys[i].indexOf('.') + 1);
            if (!"path".equals(key) && !"photoSets".equals(key) && !"location".equals(key)) { //$NON-NLS-1$ //$NON-NLS-2$
                ImageStateDescriptor state = stateAt(sequence, prefs.get(sequence + ".path", "")); //$NON-NLS-1$ //$NON-NLS-2$
                try {
                    BeanUtils.setProperty(state, key, prefs.get(keys[i], "")); //$NON-NLS-1$
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }
        // now convert the states to a list, sort it, cycle through it and add
        // them to
        // jUploadr
        List<ImageStateDescriptor> sortedStates = new ArrayList<ImageStateDescriptor>(imageStates.values());
        Collections.sort(sortedStates, new Comparator<ImageStateDescriptor>() {
            public int compare(ImageStateDescriptor o1, ImageStateDescriptor o2) {
                return o1.getRank() - o2.getRank();
            }
        });

        int progress = min;
        for (ImageStateDescriptor currentState : sortedStates) {

            if (new File(currentState.getPath()).exists()) {

                ImageAttributes atts = newAttributes(currentState.getPath(), currentState.getRotation());
                try {
                    BeanUtils.copyProperties(atts, currentState);
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                List<? extends PhotoSet> photoSets = (List<? extends PhotoSet>) fromXML(prefs, currentState.getSequence() + ".photoSets");

                if (photoSets != null && !photoSets.isEmpty()) {
                    OrganizeAbilities abilities = ImageUploadApi.getInstance().getAbilities()
                            .getOrganizeAbilities();
                    List<? extends PhotoSet> fromApi = abilities.getPhotoSets();
                    for (PhotoSet set : photoSets) {
                        if (!fromApi.contains(set)) {
                            set = ImageUploadApi.getInstance().newPhotoSet(set.getTitle(), set.getDescription(),
                                    atts);
                        } else {
                            set = fromApi.get(fromApi.indexOf(set));
                        }
                        set.addPhoto(atts);
                    }
                }
                atts.setLocation((GeoLocation) fromXML(prefs, currentState.getSequence() + ".location"));
            }

            updateProgress(progress++);
        }

        // clean up keys
        for (int i = 0; i < keys.length; i++) {
            prefs.remove(keys[i]);
        }
    }

    private Object fromXML(Preferences prefs, String key) {
        Object decoded = null;
        String xml = prefs.get(key, null);
        if (xml != null) {
            XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(xml.getBytes()));
            decoded = decoder.readObject();
        }
        return decoded;
    }

    public String getMessage() {
        return Messages.getString("juploadr.tasks.restorestate.restore"); //$NON-NLS-1$
    }

    public String getTitle() {
        return Messages.getString("juploadr.tasks.restorestate.restore"); //$NON-NLS-1$
    }

    private ImageStateDescriptor stateAt(int sequence, String path) {
        ImageStateDescriptor state = (ImageStateDescriptor) imageStates.get(path);
        if (state == null) {
            state = new ImageStateDescriptor();
            state.setPath(path);
            state.setSequence(sequence);
            imageStates.put(path, state);

        }
        return state;
    }

    private ImageAttributes newAttributes(final String path, final int rotation) {
        ReusableUIFactory.getInstance().getDisplay().syncExec(new Runnable() {
            public void run() {
                uploadr.addButton(path, rotation);
            }
        });
        return (ImageAttributes) uploadr.getImageAttributes().get(path);
    }

}